package com.zhdl.network.strategy.common_client.impl;

import cn.hutool.core.util.HexUtil;
import com.google.common.eventbus.Subscribe;
import com.project.command.faq.event.behavior.BehaviorPerform;
import com.project.command.instruction.bo.SingleInstruction;
import com.project.command.instruction.strategy.process.data.AfterStrategyParam;
import com.zhdl.common.util.IdUtil;
import com.zhdl.common.ytools.callback.CommonCallback;
import com.zhdl.common.ytools.eventbus.center.EventBusCenter;
import com.zhdl.modules.demo.hardware_connect.ReceiverMessageInterface;
import com.zhdl.network.common_client.resp.CommonClientEvent;
import com.zhdl.network.other_protocol.modbusrtu.dto.ModbusDto;
import com.zhdl.network.other_protocol.modbustcp.dto.ModbusTcpDto;
import com.zhdl.network.strategy.common_client.CommonProtocolService;
import com.zhdl.network.strategy.common_client.dto.ModbusRtuSendData;
import com.zhdl.network.strategy.common_client.dto.SendReceiverData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.project.command.instruction.strategy.abs.AbsDic.INSTRUCTION_DEFAULT_HEX;

@Slf4j
@Service
public class CommonProtocolStrategy implements CommonProtocolService {

    /**
     * RAM中的回调列表
     */
    private final Map<SendReceiverData, CopyOnWriteArrayList<ModbusRtuSendData>> callBackMap = new HashMap<>();
    /**
     * RAM中的数据
     */
    public List<SendReceiverData> sendReceiverDataList = new ArrayList<>();
    @Resource
    private BehaviorPerform behaviorPerform;
    /**
     * 是否初始化EventBus
     */
    private boolean isInit = false;

    @Resource
    ReceiverMessageInterface receiverMessageInterface;

    public void setReceiverMessageInterface(ReceiverMessageInterface receiverMessageInterface) {
        this.receiverMessageInterface = receiverMessageInterface;
    }

    @Subscribe
    public void receiverCommonData(CommonClientEvent event) {

        SendReceiverData dataByPort = getDataByPort(event.getPort());
        if (dataByPort != null) {
//            if (dataByPort.getProtocols().equals("mod-bus") && event.getProtocol().equals("mod-bus")){
            CopyOnWriteArrayList<ModbusRtuSendData> commonCallbacks = callBackMap.get(dataByPort);
            if (commonCallbacks != null && !commonCallbacks.isEmpty()) {
                //处理接受的数据
                String receiverData = HexUtil.encodeHexStr(event.getReceiveData());
                //回调数据
                processCallbacks(commonCallbacks, receiverData);
            }
//            }
        }
        if(receiverMessageInterface !=null){
            receiverMessageInterface.receiverMsg(event.getPort(),event.getReceiveData());
        }
    }

    @Subscribe
    public void dataReception(AfterStrategyParam event) {
        //端口
        String port = event.getPortKey();
        //对应的数据
        SendReceiverData dataByPort = getDataByPort(port);
        //判断是否存在这个端口
        if (dataByPort != null) {
            CopyOnWriteArrayList<ModbusRtuSendData> commonCallbacks = callBackMap.get(dataByPort);

            if (commonCallbacks != null && !commonCallbacks.isEmpty()) {
//                String receiverData = getReceiverData(event, dataByPort.getProtocols());
                /* 获取电机指令返回的数据 */
                String receiverData = null;

                //执行不同的策略
                switch (dataByPort.getProtocols()) {
                    case "modbus_tcp" -> {
                        List<ModbusTcpDto> list = event.getNewData();
                        ModbusTcpDto modbusDto = list.get(0);
                        String instruction = event.getInstruction();
                        instruction = instruction.replaceAll(" ", "");
                        receiverData = HexUtil.encodeHexStr(modbusDto.getUnitBuff());
                        if(receiverMessageInterface !=null){
                            receiverMessageInterface.receiverMsg(event.getPortKey(),modbusDto.getUnitBuff());
                        }
                        log.info("modbus_tcp");
                    }
                    case "modbus_rtu" -> {
                        List<ModbusDto> list = event.getNewData();
                        ModbusDto modbusDto = list.get(0);
                        String instruction = event.getInstruction();
                        instruction = instruction.replaceAll(" ", "");
                        receiverData = HexUtil.encodeHexStr(modbusDto.getUnitBuff());
                        if(receiverMessageInterface !=null){
                            receiverMessageInterface.receiverMsg(event.getPortKey(),modbusDto.getUnitBuff());
                        }
                    }
                    case "mod-bus" -> {
                        List<ModbusTcpDto> list = event.getNewData();
                        ModbusTcpDto modbusDto = list.get(0);
                        String instruction = event.getInstruction();
                        instruction = instruction.replaceAll(" ", "");
                        receiverData = HexUtil.encodeHexStr(modbusDto.getUnitBuff());
                        if(receiverMessageInterface !=null){
                            receiverMessageInterface.receiverMsg(event.getPortKey(),modbusDto.getUnitBuff());
                        }
                        log.info("ASCII");
                    }
                    case "memo-bus" -> {
                        log.info("火前");
                    }
                }
                if (receiverData != null && !receiverData.isEmpty()) {
                    processCallbacks(commonCallbacks, receiverData);
                }
            }
        }

    }

    /**
     * 流程回调数据
     *
     * @param commonCallbacks 消息的回调
     * @param receiverData    //接收的数据
     */
    public void processCallbacks(CopyOnWriteArrayList<ModbusRtuSendData> commonCallbacks, String receiverData) {
        int receiverPos = -1;
        for (int i = 0; i < commonCallbacks.size(); i++) {
            if (commonCallbacks.get(i).getTimeOut()==-1){
                commonCallbacks.get(i).getCallback().statusCallback(receiverData);
                receiverPos = i;
                break;
            }
            if (System.currentTimeMillis() - commonCallbacks.get(i).getSendTime() < commonCallbacks.get(i).getTimeOut()) {
                commonCallbacks.get(i).getCallback().statusCallback(receiverData);
                receiverPos = i;
                break;
            }
        }
        if (receiverPos == -1) {
            //log.info("等待消息回调队列全超时: {}", commonCallbacks);
            commonCallbacks.clear();
        } else {
            List<ModbusRtuSendData> toRemove = new ArrayList<>();
            for (int i = 0; i <= receiverPos; i++) {
                toRemove.add(commonCallbacks.get(i));
              //  log.info("清除的消息回调: {}", commonCallbacks.get(i));
            }
            commonCallbacks.removeAll(toRemove);
            //log.info("堆积回调队列: {}", commonCallbacks);
        }
    }

    /**
     * 添加 网口/串口 到RAM
     *
     * @param data 端口 后置 解析等
     */
    @Override
    public void initPort(SendReceiverData data) {
        sendReceiverDataList.add(data);
        if (!isInit) {
            EventBusCenter.getEventBus().register(this);
            isInit = true;
        }
        callBackMap.put(data, new CopyOnWriteArrayList<>());
    }

    /**
     * 发送指令 - 端口，指令，回调
     * 默认 2s超时
     *
     * @param port   端口
     * @param cmd    指令
     * @param result 回调的结果
     */
    @Override
    public void sendCmd(String port, String cmd, CommonCallback<String> result) {
        sendCmd(port, cmd, result, -1);
    }

    /**
     * 发送的指令 - 指令 端口 回调 超时时间
     *
     * @param port    端口
     * @param cmd     指令
     * @param result  回调的结果
     * @param timeOut 超时时间
     */
    @Override
    public void sendCmd(String port, String cmd, CommonCallback<String> result, int timeOut) {
        SendReceiverData portData = getDataByPort(port);
        if (portData == null) {
            return;
        }
        ModbusRtuSendData modbusRtuSendData = new ModbusRtuSendData();
        modbusRtuSendData.setCallback(result);
        modbusRtuSendData.setCmd(cmd);
        modbusRtuSendData.setTimeOut(timeOut);
        modbusRtuSendData.setTryCount(0);
        modbusRtuSendData.setSendTime(System.currentTimeMillis());
        CopyOnWriteArrayList<ModbusRtuSendData> commonCallbacks = callBackMap.get(portData);
        if (commonCallbacks != null) {
            commonCallbacks.add(modbusRtuSendData);
        }
        sendCmd(port, cmd);
    }

    /**
     * 发送的指令
     *
     * @param port 端口
     * @param cmd  指令
     */
    @Override
    public void sendCmd(String port, String cmd) {
        SendReceiverData portData = getDataByPort(port);
        if (portData == null) {
            return;
        }
        SingleInstruction instruction = new SingleInstruction();
        instruction.setInstructionId(IdUtil.getUUID_8());
        instruction.setInstruction(cmd);
        instruction.setBeforeInstructionName(INSTRUCTION_DEFAULT_HEX);
        //默认使用com.zhdl.instruction.strategy包下后置策略
        instruction.setAfterInstructionName(portData.getAfter());
        //客户端通信地址, 串口为数字, 网口为ip+端口       数据来源 : port_comm 或 port_socket 表
        instruction.setPortKey(portData.getPort());
        //设置协议  数据来源 : protocols 表
        instruction.setProtocols(portData.getProtocols());
        behaviorPerform.perform(instruction);
    }

    /**
     * 获取端口所需要的协议等内容
     *
     * @param port 端口
     * @return /
     */
    private SendReceiverData getDataByPort(String port) {
        SendReceiverData portData = null;
        for (SendReceiverData sendReceiverData : sendReceiverDataList) {
            if (port.equals(sendReceiverData.getPort())) {
                portData = sendReceiverData;
                break;
            }
        }
        if (portData == null) {
            log.info("当前 {} 未添加,请确串口/网口认配置数据!", port);
        }
        return portData;
    }

}
